===== 第 1 页 ===== 第4章 面向对象(下) · final关键字 · 多态 · JDK 8—Lambda表达式 · 垃圾回收 · 类的继承 · 抽象类和接口 · 内部类 · 异常(Exception) ===== 第 2 页 ===== 学习目标 掌握 熟悉 了解 类的继承、方法重写、super关键字的使用 final关键字、抽象类和接口以及多态的使用 JDK8的新特性—Lambda 表达式的使用 自定义异常的使用 1 2 面向对象中继承和 多态的概念 什么是异常并掌握异常的处理方式 3 ===== 第 3 页 ===== 类的继承 4.1 final关键字 4.2 ☞点击查看本小节知识架构 抽象类和接口 4.3 多态 4.4 目录 ☞点击查看本小节知识架构 ☞点击查看本小节知识架构 ☞点击查看本小节知识架构 ===== 第 4 页 ===== 内部类 4.5 JDK 8—Lambda表达式 4.6 目录 ☞点击查看本小节知识架构 异常(Exception) 4.7 ☞点击查看本小节知识架构 垃圾回收 4.8 ☞点击查看本小节知识架构 ===== 第 5 页 ===== 4.1 类的继承 4.1.1 4.1.2 继承的概念 重写父类方法 返回目录 知识架构 4.1.3 4.1.4 super关键字 Object类 ===== 第 6 页 ===== 4.2 final关键字 4.2.1 4.2.2 final关键字修饰类 final关键字修饰方法 返回目录 知识架构 4.2.3 final关键字修饰变量 ===== 第 7 页 ===== 4.3 抽象类和接口 返回目录 4.3.1 4.3.2 抽象类 接口 知识架构 ===== 第 8 页 ===== 4.4 多态 返回目录 4.4.1 4.4.2 多态概述 对象的类型转换 知识架构 ===== 第 9 页 ===== 4.5 内部类 返回目录 4.5.1 4.5.2 成员内部类 局部内部类 知识架构 4.5.3 4.5.4 静态内部类 匿名内部类 ===== 第 10 页 ===== 4.6 JDK 8—Lambda表达式 返回目录 4.6.1 4.6.2 Lambda表达式入门 函数式接口 知识架构 4.6.3 方法引用与构造器引用 ===== 第 11 页 ===== 4.7 异常(Exception) 返回目录 4.7.1 4.7.2 什么是异常 异常的类型 知识架构 4.7.3 try...catch和finally 4.7.4 throws关键字 ===== 第 12 页 ===== 4.7 异常(Exception) 返回目录 4.7.5 4.7.6 throw关键字 自定义异常 知识架构 ===== 第 13 页 ===== 4.1 类的继承 什么是继承? 在现实生活中,说到继承,多会想到子女继承父辈的财产、事业等。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关联体系。 4.1.1 继承的概念 ===== 第 14 页 ===== 4.1 类的继承 例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫继承自猫,而沙皮狗和斑点狗继承自狗。 定义:在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或基类,子类会自动拥有父类所有可继承的属性和方法。 ===== 第 15 页 ===== [修饰符] class 子类名 extends 父类名 { // 程序核心代码 } 4.1 类的继承 如果想声明一个类继承另一个类,需要使用extends关键字 案例演示(参考教材文件4-1) 类继承的语法格式: ===== 第 16 页 ===== 4.1 类的继承 在Java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类。 在Java中,多个类可以继承同一个父类。 类继承需要注意的问题: class A{} class B{} class C extends A,B{} // C类不可以同时继承A类和B类 class A{} class B extends A{} class C extends A{} // 类B和类C都可以继承类A ===== 第 17 页 ===== 4.1 类的继承 在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类。 在Java中,子类和父类是一种相对概念,也就是说,一个类是某个类父类的同时,也可以是另一个类的子类。 class A{} class B extends A{} // 类B继承类A,类B是类A的子类 class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的子类 ===== 第 18 页 ===== 4.1 类的继承 定义:在继承关系中,子类会自动继承父类中公共的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。 注意: 子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。 子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限。 案例演示(参考教材文件4-2) 4.1.2 重写父类方法 ===== 第 19 页 ===== 4.1 类的继承 问题:在继承关系中,当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。 解决方法:在Java中专门提供了一个super关键字来访问父类的成员,例如访问父类的成员变量、成员方法和构造方法。 4.1.3 super关键字 ===== 第 20 页 ===== 4.1 类的继承 使用super关键字调用父类的成员变量和成员方法。 案例演示(参考教材文件4-3&4-4) 4.1.3 super关键字——具体使用 super.成员变量 super.成员方法([参数1,参数2...]) 使用super关键字调用父类的构造方法。 super([参数1,参数2...]) ===== 第 21 页 ===== 4.1 类的继承 在Java中提供了一个Object类,它是所有类的父类,即每个类都直接或间接继承自该类。 Object类通常被称之为超类、基类或根类。 当定义一个类时,如果没有使用extends关键字为这个类显示地指定父类,那么该类会默认继承Object类。 4.1.4 Object类 ===== 第 22 页 ===== 4.1 类的继承 4.1.4 Object类——常用方法 方法声明 | 功能描述 boolean equals(Object obj) | 判断某个对象与此对象是否相等 final Class getClass() | 返回此Object的运行时类 int hashCode() | 返回该对象的哈希码值 String toString() | 返回该对象的字符串表示 void finalize() | 垃圾回收器调用此方法来清理没有被任何引用变量所引用对象的资源 案例演示(参考教材文件4-6) ===== 第 23 页 ===== 4.1 类的继承 Object类的toString()方法中输出信息格式及说明: getClass().getName() + "@" + Integer.toHexString(hashCode()); getClass().getName():代表返回对象所属类的类名,即包名+类名的全限定名称。 hashCode():代表返回该对象的哈希值。 Integer.toHexString(hashCode()):代表将对象的哈希值用16进制表示。其中, hashCode()是Object类中定义的一个方法,这个方法将对象的内存地址进行哈希运算,返回一个int类型的哈希值。 ===== 第 24 页 ===== 4.2 final关键字 final关键字可用于修饰类、变量和方法,它有“不可更改”或者“最终”的含义。因此被final修饰的类、变量和方法将具有以下特性。 final修饰的类不能被继承; final修饰的方法不能被子类重写; final修饰的变量(成员变量和局部变量)是常量,只能赋值一次。 案例演示(参考教材文件4-8&4-9&4-10) ===== 第 25 页 ===== 4.3 抽象类和接口 4.3.1 抽象类 问题:例如前面在定义Animal类时,shout()方法用于表示动物的叫声,但是不同的动物,叫声也是不同的,因此在shout()方法中无法准确描述动物的叫声。如何能使Animal类中既包含shout()方法,又无需提供其方法的实现呢? 解决方法:Java提供了抽象方法来满足这种需求。抽象方法必须使用abstract关键字来修饰,并且在定义方法时不需要实现方法体。当一个类中包含了抽象方法,那么该类也必须使用abstract关键字来修饰,这种使用abstract关键字修饰的类就是抽象类。 ===== 第 26 页 ===== 4.3 抽象类和接口 // 定义抽象类 [修饰符] abstract class 类名 { // 定义抽象方法 [修饰符] abstract 方法返回值类型 方法名([参数列表]); // 其他方法或属性 } 抽象类及抽象方法定义的语法格式: 注意:包含抽象方法的类必须定义为抽象类,但抽象类中可以不包含任何抽象方法。另外,抽象类是不可以被实例化的,如果想调用抽象类中定义的抽象方法,需要创建一个子类,在子类中实现抽象类中的抽象方法。 ===== 第 27 页 ===== 4.3 抽象类和接口 4.3.2 接口 接口是一种特殊的抽象类,它不能包含普通方法,其内部的所有方法都是抽象方法,它将抽象进行的更为彻底。 老版本接口定义 接口中除了抽象方法外,还可以有默认方法和静态方法(也叫类方法),默认方法使用default修饰,静态方法使用static修改,并且这两种方法都允许有方法体。 JDK 8接口定义 VS ===== 第 28 页 ===== 4.3 抽象类和接口 [修饰符] interface 接口名 [extends 父接口1,父接口2,...] { [public] [static] [final] 常量类型 常量名 = 常量值; [public] [abstract] 方法返回值类型 方法名([参数列表]); [public] default 方法返回值类型 方法名([参数列表]){ // 默认方法的方法体 } [public] static 方法返回值类型 方法名([参数列表]){ // 类方法的方法体 } } JDK 8接口定义的语法格式: ===== 第 29 页 ===== 4.3 抽象类和接口 修饰符可以使用public或直接省略(省略时默认采用包权限访问控制符)。 在接口内部可以定义多个常量和抽象方法,定义常量时必须进行初始化赋值,定义默认方法和静态方法时,可以有方法体。 在接口中定义常量时,可以省略“public static final”修饰符,接口会默认为常量添加“public static final”修饰符。与此类似,在接口中定义抽象方法时,也可以省略“public abstract”修饰符,定义default默认方法和static静态方法时,可以省略“public”修饰符,这些修饰符系统都会默认进行添加。 4.3.2 接口——语法定义说明 ===== 第 30 页 ===== 4.3 抽象类和接口 接口中可以包含三类方法,抽象方法、默认方法、静态方法。 静态方法可以通过“接口名.方法名”的形式来调用。 抽象方法和默认方法只能通过接口实现类的实例对象来调用。 接口的实现类,必须实现接口中的所有抽象方法。 4.3.2 接口——语法定义说明 [修饰符] class 类名 [extends 父类名] [implements 接口1,接口2,...] { ... } 案例演示(参考教材文件4-14) ===== 第 31 页 ===== 4.3 抽象类和接口 从JDK 8开始,接口中的方法除了包含抽象方法外,还包含默认方法和静态方法,默认方法和静态方法都可以有方法体,并且静态方法可以直接通过“接口.方法名”来调用。 4.3.2 接口——特点总结 当一个类实现接口时,如果这个类是抽象类,只需实现接口中的部分抽象方法即可,否则需要实现接口中的所有抽象方法。 ===== 第 32 页 ===== 4.3 抽象类和接口 一个类可以通过implements关键字同时实现多个接口,被实现的多个接口之间要用英文逗号(,)隔开。 接口之间可以通过extends关键字实现继承,并且一个接口可以同时继承多个接口,接口之间用英文逗号(,)隔开。 一个类在继承一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前。 4.3.2 接口——特点总结 ===== 第 33 页 ===== 4.4 多态 定义:在Java中,多态是指不同类的对象在调用同一个方法时所呈现出的多种不同行为。 说明:通常来说,在一个类中定义的属性和方法被其他类继承或重写后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同形态。 作用:通过多态,消除了类之间的耦合关系,大大提高了程序的可扩展性和可维护性。 4.4.1 多态概述 ===== 第 34 页 ===== 4.4 多态 注意:Java的多态性是由类的继承、方法重写以及父类引用指向子类对象体现的。由于一个父类可以有多个子类,多个子类都可以重写父类方法,并且多个不同的子类对象也可以指向同一个父类。这样,程序只有在运行时程序才能知道具体代表的是哪个子类对象,这就体现了多态性。 4.4.1 多态概述 案例演示(参考教材文件4-15) ===== 第 35 页 ===== 4.4 多态 向上转型:在多态的学习中,涉及到将子类对象当做父类类型使用的情况,此种情况在Java的语言环境中称为“向上转型”。 4.4.2 对象的类型转换 Animal an1 = new Cat(); // 将Cat类对象当做Animal类型来使用 Animal an2 = new Dog(); // 将Dog类对象当做Animal类型来使用 注意:将子类对象当做父类使用时不需要任何显式地声明,需要注意的是,此时不能通过父类变量去调用子类特有的方法。 ===== 第 36 页 ===== 4.4 多态 类型判断:Java提供了一个关键字instanceof,它可以判断一个对象是否为某个类(或接口)的实例或者子类实例。 4.4.2 对象的类型转换 对象(或者对象引用变量) instanceof 类(或接口) 案例演示(参考教材文件4-17) ===== 第 37 页 ===== 4.5 内部类 什么是内部类? 在Java中,允许在一个类的内部定义类,这样的类称作内部类,这个内部类所在的类称作外部类。 成员内部类 局部内部类 静态内部类 内部类 分类 匿名内部类 ===== 第 38 页 ===== 4.5 内部类 定义:在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。 说明:在成员内部类中,可以访问外部类的所有成员,包括成员变量和成员方法;在外部类中,同样可以访问成员内部类的变量和方法。 创建内部类对象的具体语法格式如下: 4.5.1 成员内部类 案例演示(参考教材文件4-18) 外部类名.内部类名 变量名 = new 外部类名().new 内部类名(); ===== 第 39 页 ===== 4.5 内部类 定义:局部内部类,也叫做方法内部类,就是定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其有效范围只限于方法内部。 说明:在局部内部类中,局部内部类可以访问外部类的所有成员变量和方法,而局部内部类中的变量和方法却只能在创建该局部内部类的方法中进行访问。 4.5.2 局部内部类 案例演示(参考教材文件4-19) ===== 第 40 页 ===== 4.5 内部类 定义:所谓静态内部类,就是使用static关键字修饰的成员内部类。 说明:静态内部类在成员内部类前增加了static关键字,在功能上,静态内部类中只能访问外部类的静态成员,同时通过外部类访问静态内部类成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员。 创建静态内部类对象的具体语法格式如下: 4.5.3 静态内部类 案例演示(参考教材文件4-20) 外部类名.静态内部类名 变量名 = new 外部类名.静态内部类名(); ===== 第 41 页 ===== 4.5 内部类 定义:匿名内部类其实就是没有名称的内部类。 说明:在调用包含有接口类型参数的方法时,通常为了简化代码,可以直接通过匿名内部类的形式传入一个接口类型参数,在匿名内部类中直接完成方法的实现。 4.5.4 匿名内部类 ===== 第 42 页 ===== 4.5 内部类 4.5.4 匿名内部类 案例演示(参考教材文件4-21) new 父接口(){ // 匿名内部类实现部分 } 创建匿名内部类对象的具体语法格式如下: 注意:从JDK 8开始,允许在局部内部类、匿名内部类中访问非final修饰的局部变量,而在JDK 8之前,局部变量前必须加final修饰符,否则程序编译报错。 ===== 第 43 页 ===== 4.6 JDK 8—Lambda表达式 什么是Lambda表达式? Lambda表达式是JDK 8中一个重要的新特性,它使用一个清晰简洁的表达式来表达一个接口,同时Lambda表达式也简化了对集合以及数组数据的遍历、过滤和提取等操作。 ===== 第 44 页 ===== 4.6 JDK 8—Lambda表达式 4.6.1 Lambda表达式入门 匿名内部类还有哪些缺点? 匿名内部类存在的一个问题是,如果匿名内部类的实现非常简单,例如只包含一个抽象方法的接口,那么匿名内部类的语法仍然显得比较冗余。 解决方法:可以使用JDK 8中新增的Lambda表达式,这种表达式只针对有一个抽象方法的接口实现,以简洁的表达式形式实现接口功能来作为方法参数。 ===== 第 45 页 ===== 4.6 JDK 8—Lambda表达式 4.6.1 Lambda表达式入门——语法格式 Lambda表达式基本语法格式: ([数据类型 参数名,数据类型 参数名,...]) -> {表达式主体} 用来向表达式主体内部实现的接口方法传入参数。多个参数之间用逗号分隔,可以省略数据类型,只有一个参数时还可以省略小括号 表示Lambda表达式箭牌,用来指定参数数据指向,不能省略 本质就是接口中抽象方法的具体实现。如果只有一条语句,可以省略大括号;在Lambda表达式主体中只有一条return语句时,也可以省略return关键字 案例演示(参考教材文件4-22) ===== 第 46 页 ===== 4.6 JDK 8—Lambda表达式 4.6.2 函数式接口 是否可以使用Lambda代替所有匿名内部类? 接口中有且只有一个抽象方法时才能使用Lamdba表达式代替匿名内部类。这是因为Lamdba表达式是基于函数式接口实现的,所谓函数式接口是指有且仅有一个抽象方法的接口,Lambda表达式就是Java中函数式编程的体现,只有确保接口中有且仅有一个抽象方法,Lambda表达式才能顺利地推导出所实现的这个接口中的方法。 ===== 第 47 页 ===== 4.6 JDK 8—Lambda表达式 4.6.2 函数式接口 案例演示(参考教材文件4-23) 定义:在JDK 8中,接口上标注有@FunctionalInterface注解的即为函数式接口,在函数式接口内部有且只有一个抽象方法。 说明: @FunctionalInterface注解只是显示的标注了接口是一个函数式接口,并强制编辑器进行更严格的检查,确保该接口是函数式接口。 ===== 第 48 页 ===== 4.6 JDK 8—Lambda表达式 4.6.3 方法引用与构造器引用 说明:Lambda表达式的主体只有一条语句时,程序不仅可以省略包含主体的花括号,还可以通过英文双冒号“::”的语法格式来引用方法和构造器(即构造方法)。 作用:可以进一步简化Lambda表达式的书写,其本质都是对Lambda表达式的主体部分已存在的方法进行直接引用,主要区别就是对普通方法与构造方法的引用而已。 ===== 第 49 页 ===== 4.6 JDK 8—Lambda表达式 4.6.3 方法引用与构造器引用 在JDK 8中,Lambda表达式支持的引用类型如下: 种类 | Lambda表达式示例 | 对应的引用示例 类名引用普通方法 | (x,y,...)-> 对象名x.类普通方法名(y,...) | 类名::类普通方法名 类名引用静态方法 | (x,y,...) -> 类名.类静态方法名(x,y,...) | 类名::类静态方法名 对象名引用方法 | (x,y,...) -> 对象名.实例方法名(x,y,...) | 对象名::实例方法名 构造器引用 | (x,y,...) -> new 类名 (x,y,...) | 类名::new ===== 第 50 页 ===== 4.6 JDK 8—Lambda表达式 定义:类名引用静态方法也就是通过类名对静态方法的引用,该类可以是Java自带的特殊类,也可以是自定义的普通类。 类名引用静态方法 引用示例如下: // 使用Lambda表达式方式 printAbs(-10, n -> Math.abs(n)); // 使用方法引用的方式 printAbs(-10, Math::abs); 案例演示(参考教材文件4-24) ===== 第 51 页 ===== 4.6 JDK 8—Lambda表达式 定义:对象名引用方法指的是通过实例化对象的名称来对其方法进行的引用。 对象名引用方法 引用示例如下: // 使用Lambda表达式方式 printUpper("Hello", t -> stu.printUpperCase(t)); // 使用方法引用的方式 printUpper("Hello", stu::printUpperCase); 案例演示(参考教材文件4-25) ===== 第 52 页 ===== 4.6 JDK 8—Lambda表达式 定义:构造器引用指的是对类自带的构造器的引用。 构造器引用方法 引用示例如下: // 使用Lambda表达式方式 printName("赵丽颖", name -> new Person(name)); // 使用构造器引用的方式 printName("赵丽颖", Person::new); 案例演示(参考教材文件4-26) ===== 第 53 页 ===== 4.6 JDK 8—Lambda表达式 定义:类名引用普通方法指的是通过一个普通类的类名来对其普通方法进行的引用。 类名引用普通方法 引用示例如下: // 使用Lambda表达式方式 printUpper(new StringUtils(),"Hello",(object, t) -> object.printUpperCase(t)); // 使用方法引用的方式 printUpper(new StringUtils(),"Hello",StringUtils::printUpperCase); 案例演示(参考教材文件4-27) ===== 第 54 页 ===== 4.7 异常 4.7.1 什么是异常 生活中的异常:例如感冒发烧,工作时电脑蓝屏、死机等。 程序中的异常:在程序运行的过程中,也会发生这种非正常状况,例如程序运行时磁盘空间不足、网络连接中断、被加载的类不存在等。 程序异常解决方法:针对程序中的非正常情况,Java语言中引入了异常,以异常类的形式对这些非正常情况进行封装,并通过异常处理机制对程序运行时发生的各种问题进行处理。 ===== 第 55 页 ===== 4.7 异常 4.7.1 什么是异常——异常的体系结构 称为错误,表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的,例如系统崩溃,虚拟机错误等。 称为异常类,它表示程序本身可以处理的错误。在Java程序开发中进行的异常处理,都是针对Exception类及其子类的。 ===== 第 56 页 ===== 4.7 异常 4.7.1 什么是异常——Throwable类中的常用方法 方法声明 | 功能描述 String getMessage() | 返回此throwable的详细消息字符串 void printStackTrace() | 将此throwable及其追踪输出至标准错误流 void printStackTrace(PrintStream s) | 将此throwable及其追踪输出到指定的输出流 String getMessage() | 返回此throwable的详细消息字符串 ===== 第 57 页 ===== 4.7 异常 4.7.2 异常的类型 1、编译时异常 在程序编译时期产生的异常,而这些异常必须要进行处理,也称为checked异常。 2、运行时异常 这种异常即使不编写异常处理代码,依然可以通过编译,也称为unchecked异常。 ===== 第 58 页 ===== 4.7 异常 异常类汇总:在Exception的子类中,除了RuntimeException类及其子类外,其他子类都是编译时异常。 特点:编译时异常的特点是在程序编写过程中,Java编译器就会对编写的代码进行检查,如果出现比较明显的异常就必须对异常进行处理,否则程序无法通过编译。 编译时异常 ===== 第 59 页 ===== 4.7 异常 编译时异常 处理编译时异常的方式如下: init(FilterConfig filterConfig) 1 使用try...catch语句对异常进行捕获处理; 2 使用throws关键字声明抛出异常,让调用者处理。 ===== 第 60 页 ===== 4.7 异常 异常汇总:RuntimeException类及其子类都是运行时异常。 特点:运行时异常是在程序运行时由Java虚拟机自动进行捕获处理的,即使没有使用try..catch语句捕获或使用throws关键字声明抛出,程序也能编译通过,只是在运行过程中可能报错。 运行时异常 ===== 第 61 页 ===== 4.7 异常 运行时异常 Java中常见的运行时异常如下: 异常类名称 | 异常类说明 ArithmeticException, | 算术异常 IndexOutOfBoundsException | 角标越界异常 ClassCastException | 类型转换异常 NullPointerException | 空指针异常 NumberFormatException | 数字格式化异常 ===== 第 62 页 ===== 4.7 异常 运行时异常 运行时异常错误分析:运行时异常一般是由于程序中的逻辑错误引起的,在程序运行时无法恢复。 运行时异常示例如下: int [] arr=new int[5]; System.out.println(arr[5]); ===== 第 63 页 ===== 4.7 异常 4.7.3 try...catch和finally 当程序发生异常时,会立即终止,无法继续向下执行。为了保证程序能够有效的执行,Java中提供了一种对异常进行处理的方式——异常捕获。 异常捕获try…catch语句的基本语法格式: try { // 可能发生异常的语句 } catch(Exception类或其子类 e){ // 对捕获的异常进行相应处理 } ===== 第 64 页 ===== 4.7 异常 注意:在try{}代码块中,发生异常语句后面的代码是不会被执行的。在程序中,如果希望有些语句无论程序是否发生异常都要执行,这时就可以在try…catch语句后,加一个finally{}代码块。 异常捕获try…catch...finally语句的基本语法格式: try { // 可能发生异常的语句 } catch(Exception类或其子类 e){ // 对捕获的异常进行相应处理 } finally { // 无论是否发生异常,此代码块代码总会执行 } ===== 第 65 页 ===== 4.7 异常 4.7.4 throws关键字 一般在程序开发中,开发者通常会意识到程序可能出现的问题,可以直接通过try...catch对异常进行捕获处理。但有些时候,方法中代码是否会出现异常,开发者并不明确或者并不急于处理,为此,Java允许将这种异常从当前方法中抛出,然后让后续的调用者在使用时再进行异常处理。 如果不确定或者并不急于处理异常,怎么办? ===== 第 66 页 ===== 4.7 异常 4.7.4 throws关键字 throws关键字抛出异常的基本语法格式: [修饰符] 返回值类型 方法名([参数类型 参数名1...]) throws 异常类1,异常类2,... { // 方法体... } throws关键字需要写在方法声明的后面,并在后面需要声明方法中发生异常的类型 ===== 第 67 页 ===== 4.7 异常 4.7.4 throws关键字 注意:当调用者在调用有抛出异常的方法时,除了可以在调用程序中直接进行try…catch异常处理外,也可以根据提示使用throws关键字继续将异常抛出,这样程序也能编译通过。但是,程序发生了异常,终究是需要进行处理的,如果没有被处理,程序就会非正常终止。 案例演示(参考教材文件4-31&4-32&4-33) ===== 第 68 页 ===== 4.7 异常 4.7.5 throw关键字 程序开发中,除了可以通过throws关键字抛出异常外,还可以使用throw关键字抛出异常。 throw关键字用于方法体内,并且抛出的是一个异常类对象。 throws 关键字 throws关键字用在方法声明中,用来指明方法可能抛出的多个异常。 throw 关键字 VS ===== 第 69 页 ===== 4.7 异常 4.7.5 throw关键字 说明:通过throw关键字抛出异常后,还需要使用throws关键字或try…catch对异常进行处理。 注意:如果throw抛出的是Error、RuntimeException或它们的子类异常对象,则无需使用throws关键字或try…catch对异常进行处理。 throw关键字抛出异常的基本语法格式: [修饰符] 返回值类型 方法名([参数类型 参数名,...]) throws 抛出的异常类 { // 方法体... throw new Exception类或其子类构造方法; } ===== 第 70 页 ===== 4.7 异常 4.7.6 自定义异常 Java中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况,例如在设计divide()方法时不允许被除数为负数 解决方法:Java允许用户自定义异常,但自定义的异常类必须继承自Exception或其子类。 ===== 第 71 页 ===== 4.7 异常 4.7.6 自定义异常 自定义异常的创建示例: public class DivideByMinusException extends Exception{ public DivideByMinusException (){ super(); // 调用Exception无参的构造方法 } public DivideByMinusException (String message){ super(message); // 调用Exception有参的构造方法 } } 案例演示(参考教材文件4-35&4-36) ===== 第 72 页 ===== 4.8 垃圾回收 在Java中,当一个对象成为垃圾后仍会占用内存空间,时间一长,就会导致内存空间的不足。 针对内存空间不足的情况,Java中引入了垃圾回收机制(Java GC)。 有了垃圾回收机制,程序员不需要过多关心垃圾对象回收的问题,Java虚拟机会自动回收垃圾对象所占用的内存空间。 为什么需要有垃圾回收机制? ===== 第 73 页 ===== 4.8 垃圾回收 对象在内存中的状态转换: 一个对象在彻底失去引用成为垃圾后会暂时地保留在内存中,当这样的垃圾堆积到一定程度时,Java虚拟机就会启动垃圾回收器将这些垃圾对象从内存中释放,从而使程序获得更多可用的内存空间。 ===== 第 74 页 ===== 4.8 垃圾回收 注意:虽然通过程序可以控制一个对象何时不再被任何引用变量所引用,但是却无法精确的控制Java垃圾回收的时机。 回收方式:除了等待Java虚拟机进行自动垃圾回收外,还可以通知系统垃圾回收器进行垃圾回收。 init(FilterConfig filterConfig) 1 调用System类的gc()静态方法:System.gc()。 2 调用Runtime对象的gc()实例方法:Runtime.getRuntime.gc()。 通知系统回收器的方式 说明:以上两种方式可以通知启动垃圾回收器进行垃圾回收,但是否立即进行垃圾回收依然具有不确定性。多数情况下,执行后总是有一定的效果。 ===== 第 75 页 ===== 4.8 垃圾回收 当一个对象在内存中被释放时,它的finalize()方法会被自动调用,finalize()方法是定义在Object类中的实例方法。 任何Java类都可以重写Object类的finalize()方法,在该方法中清理该对象占用的资源。如果程序终止之前仍然没有进行垃圾回收,则不会调用失去引用对象的finalize()方法来清理资源 只有当程序认为需要更多的额外内存时,垃圾回收器才会自动进行垃圾回收。 案例演示(参考教材文件4-37) ===== 第 76 页 ===== 4.9 本章小结 本章详细讲解了面向对象的基础知识。首先讲解了面向对象的思想,然后讲解了类与对象之间的关系,接着讲解了方法的重载与递归、构造方法和this关键字的使用,最后讲解了static关键字的使用。 ===== 第 77 页 =====